<?php
/*
 * Created on 11/ago/2008
 *
 * @package mikrokosmos
 * @author jaco_at_pixeldump
 * @description "hi level" classes to ease repetitive tasks
 */

if(!class_exists("MKTagHeader")){ class MKTagHeader {}}


class MKSwfComposer extends MKSwf {

	var $fc = array();		// array of frameComposers

	// the constructor
	function MKSwfComposer() {
	}

	function expand_timeline($numberOfFrames = 1){
		for($i = 0; $i < $numberOfFrames; $i++) $this->fc[] = new MKFrameComposer();
	}

	function reduce_timeline($numberOfFrames = 1){
		for($i = 0; i < $numberOfFrames; $i++) array_pop($this->fc);
	}

	function insert_frameAt($index = 0){
		/* TODO */
	}

	function remove_frameAt($index = 0){
		/* TODO */
	}

	function get_frameByIndex($index = 0){
		/* TODO */
	}

	function add_frameComposer(){
		/* TODO */
	}

	function save() {
		/* TODO */
	}
}


class MKFrameComposer extends SwfFrame {


	function MKFrameComposer(){
	}
}


class MKBitmapAssetComposer {

	var $swfVersion = 8;
	var $symbolName;
	var $swfFN;
	var $imageFN;
	var $alphaFN;
	var $imageDir = SERVER_MKIMAGES;
	var $alphaDir = SERVER_MKIMAGES;

	var $swf;
	var $bmp;

	var $bmpWidth;
	var $bmpHeight;

	// < swf9
	var $sc;	// shape
	var $mc;	// movieclip

	// >= swf9
	var $sn;	// sceneNames
	var $dab;	// dummmyAS3BitmapClass
	var $cn;	// classNames
	var $po3;

	// the constructor
	function MKBitmapAssetComposer($swfVersion, $symbolName, $swfFN, $imageFN, $alphaFN = "",
									$imageDir = SERVER_MKIMAGES,
									$alphaDir = SERVER_MKIMAGES){

		$this->swfVersion = $swfVersion;
		$this->symbolName = $symbolName;
		$this->swfFN = $swfFN;
		$this->imageFN = $imageFN;
		$this->alphaFN = $alphaFN;
		$this->imageDir = $imageDir;
		$this->alphaFN = $alphaFN;
		$this->alphaDir = $alphaDir;

		$bs = getimagesize($imageDir .$imageFN);
		$this->bmpWidth = $bs[0];
		$this->bmpHeight = $bs[1];
		$this->swf = new MKSwf($swfFN, $swfVersion, $bs[0], $bs[1]);
		$this->swf->set_isCompressed("yes");

		$this->bmp = new BitmapItem();
	}

	//
	function build_bitmapTag($quality = 100){

		if(strlen($this->alphaFN)){
			$this->bmp->set_image_source($this->imageFN, $this->imageDir);
			$this->bmp->load_alpha_from_file($this->alphaFN, $this->alphaDir);

			$bmpTD = $this->bmp->update_lossy_tagData($quality);
		}
		else $bmpTD = $this->bmp->create_from_file($this->imageFN, $this->imageDir, $quality);

		return $bmpTD;
	}

	//
	function compose_AVM2Asset($bmpTD, $saveAsSprite = false){
		$this->swf->set_AS3_flag(true);

		$this->dab = new DummyAs3BitmapClass($this->symbolName);
		$this->sn = new MKSceneNames("", array("MKScene01"));
		$this->cn = new MKClassNames("");
		$this->cn->add_class_definition($this->symbolName);

		$snTD = $this->sn->update_tagData();
		$dabTD = $this->dab->update_tagData();
		$cnTD = $this->cn->update_tagData();

		$this->swf->add_tagData($snTD);
		$this->swf->add_tagData($dabTD);
		$this->swf->add_tagData($bmpTD);
		$this->swf->add_tagData($cnTD);

		if($saveAsSprite){
			$this->po3 = new MKPlaceObject3("", 1, 1, 1, true);
			$this->po3->set_pfHasCacheAsBitmap(true);
			$po3TD = $this->po3->update_tagData();
			$this->swf->add_tagData($po3TD);
		}
	}

	//
	function compose_AVM1Asset($bmpTD){

		$this->sc = new MKShapeContainer("", 2);

		$mad = array();
		$mad["x"] = 0;
		$mad["y"] = 0;
		$mad["width"] = $this->bmpWidth;
		$mad["height"] = $this->bmpHeight;
		$sc->add_bitmap_fill(1, CLIPPED_BITMAP_FILL, $mad);
		$sc->add_rect($mad["x"], $mad["y"], $mad["width"], $mad["height"]); // image bounding box

		$this->mc = new MKMovieClip("", 3);
		$this->sc->add_tagData($this->sc->update_place_tagData());
		$mcEoTD = $this->mc->set_linkage_name($this->symbolName);
		$mcTD = $this->mc->update_tagData();

		$this->swf->add_tagData($bmpTD);
		$this->swf->add_tagData($mcTD);
		$this->swf->add_tagData($mcEoTD);
	}

	//
	function save($quality = 100, $saveAsSprite = false){
		$bmpTD = $this->build_bitmapTag($quality);

		if($this->swfVersion <= 8) $this->compose_AVM1Asset($bmpTD);
		else $this->compose_AVM2Asset($bmpTD, $saveAsSprite);

		$this->swf->save();
	}
}


/**
 * create an swf with a symbolName
 * 	Sprite, MovieClip for AVM1/2, depending on $swfVersion value
 *
 */
class MKDisplayObjectAssetComposer {

	var $swfVersion = 8;
	var $symbolName;
	var $swfFN = SWF_DEFAULT_NAME;
	var $svgFN = "";
	var $svgDir = SERVER_MKSVG;
	var $svgAr = array();			// list of svg files to build mc
									// each item is: svg -> an MKSimpleSvgReader instance
									// 				 svgFN -> its source filename,
									//			   			  used for indexing
	var $frameNumber = 0;			// mc timeline working frame
	var $depthAr = array();			// array of involved depth

	var $flFN = "";					// movieclip frame list source file

	var $swf;
	var $svg;
	var $po2;	// used to place mc on stage

	// < swf9
	var $mc;	// movieclip

	// >= swf9
	var $sn;	// sceneNames
	var $dab;	// dummmyAS3DisplayObjectClass
	var $cn;	// classNames
	var $sc;	// shape


	function MKDisplayObjectAssetComposer($swfVersion, $symbolName, $svgFN = "", $svgDir = SERVER_MKSVG){

		$this->swfVersion = $swfVersion;
		$this->symbolName = $symbolName;

		if(strlen($svgFN)) {
			$this->svgFN = $svgFN;
			$this->swfFN = basename($svgFN, ".svg") .".swf";
		}

		$this->svgDir = $svgDir;
		$this->swf = new MKSwf($this->swfFN, $swfVersion);
		$this->swf->set_isCompressed("yes");
	}

	//
	function set_mc($mc) {
		$this->mc = $mc;
		$this->classState = 1; // means "no mc build needed" /* TODO */
	}
	function get_mc() { return $this->mc; }

	//
	function set_fps($fps = 31) { $this->swf->set_fps($fps); }

	function timeline_from_directory ($svgArDir = SERVER_MKSVG){

		$placeDepth = 1;
		$this->svgDir = $svgArDir;

		if(!file_exists($svgArDir)) {
			log_write_entry(get_class($this) .": cannot build mc timeline from invalid svg directory");
			return;
		}

		$svgFiles = get_fileList($svgArDir, ".svg", false);
		$sCount = count($svgFiles);
		$idx = $this->add_svgItem($svgFiles[0]);
		$svg = $this->svgAr[$idx]["svg"];

		$this->mc = new MKMovieClip("", count($svgFiles) + 1);
		$this->mc->add_tagData($svg->update_place_tagData());
		$this->swf->set_stageSize($svg->get_svgWidth(), $svg->get_svgHeight());

		for($i = 1; $i < $sCount; $i++){
			$idx = $this->add_svgItem($svgFiles[$i]);
			$svg = $this->svgAr[$idx]["svg"];

			$this->mc->add_tagData($svg->update_place_tagData($placeDepth), $i + 1);
		}
	}

	//
	function create_mc_from_file($flFN = "", $flDir = SERVER_MKCODE){

		$flPath = $flDir .$flFN;

		$flXml = new XmlLib_xmlParser($flDir .$flFN);
 		$doc = & $flXml->getDocument();
		$this->mc = new MKMovieClip();

		if($doc->nodeName == "framelist"){
			$this->parse_frameList($doc, $flDir);
			$this->mc->set_itemID(count($this->svgAr) + 1);
		}
	}

	//
	function parse_frameList($flNode, $flDir){

			$allowedTags = array("frameblock", "frame");

			$w = (int) $flNode->getAttribute("width");
			$h = (int) $flNode->getAttribute("height");
			if($w && $h) $this->swf->set_stageSize($w, $h);

			$useAS3 = $flNode->getAttribute("useAS3");
			if($useAS3) $this->swf->set_AS3_flag((bool) $useAS3);

			$fps = (int) $flNode->getAttribute("fps");
			if($fps) $this->swf->set_fps($fps);

			$bgColor = $flNode->getAttribute("backgroundColor");
			if($bgColor) $this->swf->set_backgroundColor(($bgColor));

			$source = $flNode->getAttribute("source");
			//if($source == ".") $this->svgDir = $flDir;	// TODO: fix this in case of parent (../ and so on) directories
			if($source == ".") $this->svgDir = $flDir;

			$fl = $flNode->childNodes();

			foreach($fl as $f){

				$fName = $f->nodeName;

				if(in_array($fName, $allowedTags, true)){

					$evStr = "\$this-" .">parse_" .$fName ."(\$f);";

					eval($evStr);
				}
			}
	}

	//
	function parse_frameblock($fbNode) {

		$fNodes = array();
		$frames = array();

		$repeatType = $fbNode->getAttribute("repeat");
		$duration = $fbNode->getAttribute("duration");

		$repeatType = ($repeatType) ? $repeatType: "count";
		$duration = ($duration) ? $duration : 1;
		$fBlock = $fbNode->childNodes();

		// collect frame
		foreach($fBlock as $f){
			if($f->nodeName == "frame") $fNodes[] = $f;
		}

		$fCount = count($fNodes);

		if(strpos($duration, ":") !== false){ // duration is time based

			$fbNodeps = $this->swf->get_fps();
			$timeAr = split(":", $duration);
			$msec = (int) $timeAr[0] * 60000 + (int) $timeAr[1] * 1000 + (int) $timeAr[2];

			$mpf = 1000 / $fbNodeps;
			$totalFrameCount = floor($msec / $mpf);
		}
		else $totalFrameCount = $duration * $fCount; // duration is frame count based

		for($i = 0, $k = 0; $i < $totalFrameCount; $i++){
			/* TODO: manage repeatType:random */
			$frames[] = $fNodes[$k++];

			if($k >= $fCount) $k = 0;
		}

		if($repeatType == "randomGlobal") shuffle($frames);

		for($i = 0; $i < $totalFrameCount; $i++){
			$fNode = $frames[$i];
			$fNode->setAttribute("number", ($i + 1));
			$this->parse_frame($fNode);
		}
	}

	//
	function parse_frame($fNode) {

		$cNodes = $fNode->childNodes();
		$this->frameNumber++;

		if(count($cNodes)){

			foreach($cNodes as $c){
				if($c->nodeName == "svg") {

					$svg = $this->parse_svgNode($c);

					if($this->frameNumber > 1) {
						$placeDepth = max($c->getAttribute("depth"), 1);
						$this->mc->add_tagData($svg->update_place_tagData($placeDepth), $this->frameNumber);
						continue;
					}

					$this->mc->add_tagData($svg->update_place_tagData());
				}
			}
		}
		else $this->mc->add_frameData();
	}

	//
	function parse_svgNode($sNode){

		$svgFN = $sNode->getAttribute("source");
		$idx = $this->add_svgItem($svgFN);
		$svg = $this->svgAr[$idx]["svg"];

		$x = (float) $sNode->getAttribute("x");
		$y = (float) $sNode->getAttribute("y");
		$scaleX = (float) $sNode->getAttribute("scaleX") * 100;
		$scaleY = (float) $sNode->getAttribute("scaleY") * 100;
		$rotate = (float) $sNode->getAttribute("rotate");

		$x = ($x) ? $x : 0;
		$y = ($y) ? $y : 0;
		$scaleX = ($scaleX) ? $scaleX : 1;
		$scaleY = ($scaleY) ? $scaleY : 1;
		$rotate = ($rotate) ? $rotate : 0;

		if($x || $y) $svg->move($x, $y);
		if($scaleX != 1 || $scaleY != 1) $svg->scale($scaleX, $scaleY);
		if($rotate) $svg->rotate($rotate);

		$this->svgAr[$idx]["svg"] = $svg;

		return $svg;
	}

	// add an svg to svgAr, if there are not duplicates
	// return the index of svgItem added
	function add_svgItem($svgFN){

		$sCount = count($this->svgAr);
		$svgFileNames = array();

		for($i = 0; $i < $sCount; $i++)
			$svgFileNames[] = $this->svgAr[$i]["svgFN"];

		if(!$sCount || !in_array($svgFN, $svgFileNames, true)){ // item will be added
			$svgItem = array();
			$svgItem["svg"] = new MKSimpleSvgReader($svgFN, $this->svgDir, $sCount + 1);
			$svgItem["svgFN"] = $svgFN;

			$this->svgAr[] = $svgItem;
			return $sCount;
		}

		for($i = 0; $i < $sCount; $i++){
			$svgFileNames[] = $this->svgAr[$i]["svgFN"];
			if($svgFileNames[$i] == $svgFN) return $i; // the requested item is already present, return its index
		}

		log_write_entry(get_class($this) .": ERROR in add_svgItem");
		return -1; // ERROR
	}

	//
	function build_mc(){

		$this->mc = new MKMovieClip("", 2);
		$this->svg = new MKSimpleSvgReader($this->svgFN, $this->svgDir);
		$svgPoTD = $this->svg->update_place_tagData();

		$this->swf->set_stageSize($this->svg->get_svgWidth(), $this->svg->get_svgHeight());
		$this->mc->add_tagData($svgPoTD);
	}

	//
	function compose_AVM1Asset($placeOnStage = false){

		if(count($this->svgAr)){
			foreach($this->svgAr as $svg)
				$svgTDs[] = $svg->update_tagData();
		}
		else $svgTDs = array($this->svg->update_tagData());


		$mcTD = $this->mc->update_tagData();
		$mcEoTD = $this->mc->set_linkage_name($this->symbolName);

		foreach($svgTDs as $svgTD)
			$this->swf->add_tagData($svgTD);

		$this->swf->add_tagData($mcTD);
		$this->swf->add_tagData($mcEoTD);

		if($placeOnStage) $this->swf->add_tagData($this->mc->update_place_tagData());
	}

	//
	function compose_AVM2Asset($placeOnStage = false){

		$mcID = $this->mc->get_itemID();
		$this->swf->set_AS3_flag(true);

		$this->sn = new MKSceneNames("", array("MKScene01"));
		$this->cn = new MKClassNames("");
		$this->cn->add_class_definition($this->symbolName, $mcID);

		$this->dab = new DummyAs3DisplayObjectClass($this->symbolName);

		$snTD = $this->sn->update_tagData();
		$dabTD = $this->dab->update_tagData();

		$svgTDs = array();

		if(count($this->svgAr)){
			foreach($this->svgAr as $svgItem)
				$svgTDs[] = $svgItem["svg"]->update_tagData();
		}
		else $svgTDs = array($this->svg->update_tagData());

		$mcTD = $this->mc->update_tagData();
		$cnTD = $this->cn->update_tagData();

		$this->swf->add_tagData($snTD);
		$this->swf->add_tagData($dabTD);

		foreach($svgTDs as $svgTD)
			$this->swf->add_tagData($svgTD);

		$this->swf->add_tagData($mcTD);

		//$mc = new MKMovieClip("", 6);
		//$mcTD = $mc->update_tagData();
		//$this->swf->add_tagData($mcTD);

		$this->swf->add_tagData($cnTD);

		if($placeOnStage){
			$this->po2 = new MKPlaceObject2("", 1, $mcID);
			$this->po2->set_name("my" .$this->symbolName);
			$po2TD = $this->po2->update_tagData();
			$this->swf->add_tagData($po2TD);
		}
	}

	//
	function save($placeOnStage = false, $swfFN = "", $swfDir = ""){

		if(strlen($swfFN))
			$this->swf->set_swfFileName(basename($swfFN, ".swf") .".swf");

		if(strlen($swfDir)) $this->swf->set_swfDir($swfDir);

		if(strlen($this->svgFN)) $this->build_mc();

		if($this->swfVersion <= 8) $this->compose_AVM1Asset($placeOnStage);
		else $this->compose_AVM2Asset($placeOnStage);

		$this->swf->save();
	}
}

?>
